using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;

namespace Cirrostrata.Abstractions.Net
{
    public class HttpQuery : IHttpQuery
    {
        private string _method;
        private readonly Dictionary<string, string> _formFields = new Dictionary<string, string>();
        private Uri _uri;
        private byte[] _data;
        private byte[] _result;
        private string _contentType = "application/x-www-form-urlencoded";
        private string _cookie;
        private bool _keepCookies;
        private ICredentials _credentials;
        private HttpStatusCode _status;

        public IHttpQuery Post(Uri uri)
        {
            _method = "POST";
            _uri = uri;
            return this;
        }

        public IHttpQuery Get(Uri uri)
        {
            _method = "GET";
            _uri = uri;
            return this;
        }

        public IHttpQuery Put(Uri uri)
        {
            _method = "PUT";
            _uri = uri;
            return this;
        }

        public IHttpQuery Delete(Uri uri)
        {
            _method = "DELETE";
            _uri = uri;
            return this;
        }

        public IHttpQuery ContentType(string contentType)
        {
            _contentType = contentType;

            return this;
        }

        public IHttpQuery Data(byte[] data)
        {
            _data = data;
            return this;
        }

        public IHttpQuery SetFormField(string field, string value)
        {
            _formFields.Add(field, value);
            return this;
        }

        public IHttpQuery KeepCookies
        {
            get
            {
                _keepCookies = true;
                return this;
            }
        }

        public IHttpQuery DiscardCookies
        {
            get
            {
                _keepCookies = false;
                return this;
            }
        }

        public IHttpQuery WithCredentials(ICredentials credentials)
        {
            _credentials = credentials;
            return this;
        }

        public byte[] Result
        {
            get { return _result; }
        }

        public string ResultText
        {
            get { return Encoding.Default.GetString(_result); }
        }

        public HttpStatusCode Status
        {
            get { return _status; }
        }

        public IHttpQuery Go()
        {
            WebRequest req = WebRequest.Create(_uri.OriginalString);

            if (_keepCookies && _cookie != null)
                req.Headers.Set("Cookie", _cookie);

            req.Method = _method;

            if (_formFields.Count > 0)
            {
                var dataStr = new StringBuilder();

                foreach (string key in _formFields.Keys)
                {
                    string value = _formFields[key];

                    if (dataStr.Length > 0)
                        dataStr.Append('&');

                    dataStr.AppendFormat("{0}={1}", Uri.EscapeDataString(key), Uri.EscapeDataString(value));
                }

                if (_data != null && _data.Length > 0)
                {
                    dataStr.Insert(0, '&');
                    byte[] dataBin = Encoding.Default.GetBytes(dataStr.ToString());

                    var oldData = new byte[_data.Length];

                    Array.Copy(_data, oldData, _data.Length);

                    _data = new byte[oldData.Length + dataBin.Length];

                    Array.Copy(oldData, _data, oldData.Length);
                    Array.Copy(dataBin, 0, _data, oldData.Length, dataBin.Length);
                }
                else
                {
                    _data = Encoding.Default.GetBytes(dataStr.ToString());
                }
            }

            if (_data != null)
            {
                req.ContentType = _contentType;
                req.ContentLength = _data.Length;
                req.GetRequestStream().Write(_data, 0, _data.Length);
            }
            else
                req.ContentLength = 0;

            if (_credentials != null)
                req.Credentials = _credentials;

            var res = (HttpWebResponse)req.GetResponse();

            _status = res.StatusCode;

            if (_keepCookies)
            {
                string setCookie = res.Headers["Set-Cookie"];

                if (setCookie != null)
                    _cookie = setCookie;
            }

            var ms = new MemoryStream();

            res.GetResponseStream().CopyTo(ms);

            _result = ms.ToArray();
            _data = null;
            _formFields.Clear();

            if (!_keepCookies)
                _cookie = null;

            return this;
        }
    }
}